#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/12/18 21:05
# @Author  : lizhen
# @Site    : 
# @File    : CSingleton.py
# @Software: PyCharm
import threading
import time


def SingletonEnclosure(cls):
    _instance = {}

    def _singleton(*args, **kargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kargs)
        return _instance[cls]

    return _singleton


@SingletonEnclosure
class SingletonEnclosureCls(object):
    pass


class SingletonClsVars(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(SingletonClsVars, "_instance"):
            with SingletonClsVars._instance_lock:
                if not hasattr(SingletonClsVars, "_instance"):
                    SingletonClsVars._instance = SingletonClsVars(*args, **kwargs)
        return SingletonClsVars._instance


class SingletonClsVarsNew(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)

    def __new__(cls, *args, **kwargs):
        if not hasattr(SingletonClsVarsNew, "_instance"):
            with SingletonClsVarsNew._instance_lock:
                if not hasattr(SingletonClsVarsNew, "_instance"):
                    SingletonClsVarsNew._instance = super().__new__(cls, *args, **kwargs)
        return SingletonClsVarsNew._instance


class SingletonMetaclass(type):
    _instance_lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with SingletonMetaclass._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super(SingletonMetaclass, cls).__call__(*args, **kwargs)
        return cls._instance


class SingletonMetaclassCls(metaclass=SingletonMetaclass):
    pass


class SingletonDemo:
    def _test_singleton_import(self):
        """
        sd = SingletonDemo()
        sd._test_singleton_import()
        """
        from cOuterModule import singleton_import
        st1 = singleton_import
        from cOuterModule import singleton_import
        st2 = singleton_import
        print(st1 is st2)

    def _test_singleton_enclosure(self):
        """
        sd = SingletonDemo()
        sd._test_singleton_enclosure()
        """
        st1 = SingletonEnclosureCls()
        st2 = SingletonEnclosureCls()
        print(st1 is st2)

    def _test_singleton_cls_vars(self):
        """
        sd = SingletonDemo()
        sd._test_singleton_cls_vars()
        """
        st1 = SingletonClsVars.instance()
        st2 = SingletonClsVars.instance()
        print(st1 is st2)

    def _test_singleton_cls_vars_new(self):
        """
        sd = SingletonDemo()
        sd._test_singleton_cls_vars_new()
        """
        st1 = SingletonClsVarsNew()
        st2 = SingletonClsVarsNew()
        print(st1 is st2)

    def _test_singleton_metaclass(self):
        """
        sd = SingletonDemo()
        sd._test_singleton_metaclass()
        """
        st1 = SingletonMetaclassCls()
        st2 = SingletonMetaclassCls()
        print(st1 is st2)


if __name__ == '__main__':
    sd = SingletonDemo()
    sd._test_singleton_metaclass()
